﻿using AesonBaseFramework.Annotations;
using AesonBaseFramework.EntityFramework.Validation;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace AesonBaseFramework.EntityFramework.BaseEntities
{
    public abstract class AesonBaseEntity : INotifyPropertyChanged, IAesonBaseEntity, INotifyDataErrorInfo
    {
        protected AesonBaseEntity()
        {
        }

        [Required]
        public int Id { get; set; }

        public DateTime DateCreate { get; set; }

        public DateTime DateModified { get; set; }

        public string UserCreated { get; set; }

        public string UserModified { get; set; }

        [NotMapped]
        public bool IsDirty { get; set;  }

        #region Validation

        public List<ValidationResult> ValidateProperty(string propertyName, object value)
        {
            var validationResults = new List<ValidationResult>();
            if (propertyName != "")
            {
                var validationContext = new ValidationContext(this, null, null);
                validationContext.MemberName = propertyName;
                try
                {
                    Validator.TryValidateProperty(value, validationContext, validationResults);
                }
                catch (Exception)
                {
                }
            
               
            }
          
            return validationResults;


        }

        public virtual IEnumerable<ValidationResult> Validate()
        {
            return EntityValidator.ValidateEntity(this);
        }

        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public void RaiseErrorsChanged(string propertyName)
        {
            EventHandler<DataErrorsChangedEventArgs> handler = ErrorsChanged;
            if (handler == null) return;
            var arg = new DataErrorsChangedEventArgs(propertyName);
            handler.Invoke(this, arg);
        }

        public IEnumerable GetErrors(string propertyName)
        {
            return _errors.Where((p => p.Key == propertyName)).AsEnumerable();
        }

        public IEnumerable GetEntityErrors()
        {
            return _errors.AsEnumerable();
        }

        public bool HasErrors
        {
            get { return _errors.Count != 0; }
        }

     
        

        #endregion Validation

        #region PropertyChange

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual async void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.IsDirty = true;
            this.DateModified = DateTime.Now;

            #region Validate complete entity

            await Task.Factory.StartNew(() =>
            {
                _errors = new Dictionary<string, string>();
                foreach (var r in this.Validate())
                {
                    foreach (string prop in r.MemberNames)
                    {
                        _errors.Add(prop, r.ErrorMessage);
                        RaiseErrorsChanged(prop);
                    }
                }
            });

            #endregion Validate complete entity

            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion PropertyChange
    }
}